package com.esdk.utils;

import com.esdk.esdk;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

public class BeanToMapConfig{
  private boolean ignoreNull=true;
  private boolean ordered=true;
  private boolean usePropertyName=true;
  private boolean recursive=true;
  private boolean snowIdToStr=true;
  private boolean formatDateTime;
  private String DateTimeTempalte=esdk.time.DATETIME_FORMAT;
  private Map<Class,Function> handlers;
  private static BeanToMapConfig defaultConfig,renderConfig;

  public BeanToMapConfig(){

  }

  public static BeanToMapConfig defaultConfig(){
    if(defaultConfig==null){
      defaultConfig=new BeanToMapConfig();
    }
    return defaultConfig;
  }

  public static BeanToMapConfig renderConfig(){
    if(renderConfig==null){
      renderConfig=new BeanToMapConfig().setSnowIdToStr(true).setFormatDateTime(true);
    }
    return renderConfig;
  }

  public boolean isIgnoreNull(){
    return ignoreNull;
  }

  public BeanToMapConfig setIgnoreNull(boolean ignoreNull){
    this.ignoreNull=ignoreNull;
    return this;
  }

  public boolean isUsePropertyName(){
    return usePropertyName;
  }

  public BeanToMapConfig setUsePropertyName(boolean usePropertyName){
    this.usePropertyName=usePropertyName;
    return this;
  }

  public boolean isRecursive(){
    return recursive;
  }

  public BeanToMapConfig setRecursive(boolean recursive){
    this.recursive=recursive;
    return this;
  }

  public <T,R> BeanToMapConfig addHandler(Class<T> clazz,Function<T,R> func){
    if(handlers==null){
      handlers=new HashMap<>();
    }
    handlers.put(clazz,func);
    return this;
  }

  public Map<Class,Function> getHandlers(){
    return handlers;
  }

  public boolean isOrdered(){
    return ordered;
  }

  public void setOrdered(boolean ordered){
    this.ordered=ordered;
  }

  public String getDateTimeTempalte(){
    return DateTimeTempalte;
  }

  public BeanToMapConfig setDateTimeTempalte(String dateTimeTempalte){
    DateTimeTempalte=dateTimeTempalte;
    return this;
  }

  public boolean isSnowIdToStr(){
    return snowIdToStr;
  }

  public BeanToMapConfig setSnowIdToStr(boolean snowIdToStr){
    this.snowIdToStr=snowIdToStr;
    if(snowIdToStr){
      this.addHandler(Long.class, parm->{
        if(this.snowIdToStr && esdk.sql.isSnowId(parm))
          return parm.toString();
        else return parm;
      });
    }
    else{
      if(this.containsKey(Long.class))
        this.handlers.remove(Long.class);
    }
    return this;
  }

  public boolean containsKey(Class<?> aClass){
    if(handlers==null)
      return false;
    else
      return handlers.containsKey(aClass);
  }

  public boolean isFormatDateTime(){
    return formatDateTime;
  }

  public BeanToMapConfig setFormatDateTime(boolean formatDateTime){
    this.formatDateTime=formatDateTime;
    if(formatDateTime){
      this.addHandler(Date.class,parm->{
        return esdk.time.format(parm,renderConfig.DateTimeTempalte);
      });
      this.addHandler(LocalDateTime.class,parm->{
        return parm.toString().replace("T"," ");
      });
    }else{
      if(this.containsKey(Date.class))
        this.handlers.remove(Date.class);
      if(this.containsKey(LocalDateTime.class))
        this.handlers.remove(LocalDateTime.class);
    }
    return this;
  }
}
